package sc.common.test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

/**
 * 任务计时器
 * 用于记录互斥任务（步骤）各自运行时间
 * 多线程不安全
 */
public class JobStopWatchBack {

    public JobStopWatchBack(String watchName) {
        this.watchName = watchName;
    }

    String watchName;

    HashMap<String, Job> jobs = new HashMap<String, JobStopWatchBack.Job>();

    public static class Job {
        public Job(String jobName) {
            this.jobName = jobName;
            this.isRunning = false;
            this.runMillis = 0;
        }

        public void begin() {
            if (isRunning) {
                return;
            } else {
                if (beginTime == null) {
                    beginTime = new Date();
                    stageCount = 1;
                } else {
                    lastEndTime = new Date();
                    stageCount++;
                }
                isRunning = true;
            }
        }

        public void end() {
            if (!isRunning) {
                return;
            } else {
                Date now = new Date();
                if (lastEndTime == null) {
                    runMillis += (now.getTime() - beginTime.getTime());
                } else {
                    runMillis += (now.getTime() - lastEndTime.getTime());
                }
                lastEndTime = now;
                isRunning = false;
            }
        }

        public long getRunMillis() {
            if (!isRunning) {
                return runMillis;
            } else {
                return new Date().getTime() - beginTime.getTime() + runMillis;
            }
        }

        public String jobName;
        public Date beginTime;
        public Date lastEndTime;
        public int stageCount;
        public long runMillis;
        public boolean isRunning;

        @Override
        public boolean equals(Object obj) {
            return jobName.endsWith(((Job) obj).jobName);
        }
    }

    Job curJob;

    /**
     * 切换步骤开始
     * @param job 步骤唯一标识
     */
    public void begin(String jobName) {
        Job theJob = jobs.get(jobName);
        if (theJob == null) {
            theJob = new Job(jobName);
            jobs.put(jobName, theJob);
        }
        if (curJob != null) {
            curJob.end();
        }
        theJob.begin();
        curJob = theJob;
    }

    /**
     * 当前步骤结束
     */
    public void end() {
        if (curJob == null) {
            return;
        }
        curJob.end();
        curJob = null;
    }

    public static class BeginTimeComparator implements Comparator<Job> {
        @Override
        public int compare(Job o1, Job o2) {
            return o1.beginTime.compareTo(o2.beginTime);
        }
    }


    @Override
    public String toString() {
        List<Job> jobsLog = new ArrayList<Job>(jobs.values());
        Collections.sort(jobsLog, new BeginTimeComparator());
        StringBuffer sb = new StringBuffer("JobStopWatch");
        sb.append("<").append(watchName).append(">\r\n");
        Iterator<Job> it = jobsLog.iterator();
        long sumMillis = 0;
        while (it.hasNext()) {
            Job job = it.next();
            long jobMillis = job.getRunMillis();
            sb.append(
                    String.format("name[%-40s], stageCount[%3d], runMillis[%10dms], begin[%23s], end[%23s]",
                            job.jobName, job.stageCount, jobMillis, DateUtil.formatDetail(job.beginTime),
                            DateUtil.formatDetail(job.lastEndTime))).append("\r\n");
            sumMillis += jobMillis;
        }
        sb.append("statistic: ").append("count = ").append(jobs.size());
        sb.append(", sumMillis = ").append(sumMillis);
        sb.append("\r\n");
        return sb.toString();
    }

    public static void main(String[] args) throws InterruptedException {
        JobStopWatchBack w = new JobStopWatchBack("Test Watch");
        w.begin("Job A");
        Thread.sleep(100);
        w.begin("Job B");
        Thread.sleep(200);
        w.begin("Job C");
        Thread.sleep(300);
        System.out.print(w);
        w.begin("Job A");
        Thread.sleep(400);
        System.out.print(w);
        w.begin("Job C");
        Thread.sleep(500);
        System.out.print(w);
    }
}
